package service

import (
	"github.com/olahol/melody"
	"sync"
	"time"
	"yun_image/entity"
	"yun_image/util"
)

type chatInfoMaps struct {
	userSession      map[string]*melody.Session
	sessionUser      map[*melody.Session]string
	userChatRooms    map[string]map[*entity.ChatRoom]bool
	idChatRoom       map[string]*entity.ChatRoom
	chatRoomSessions map[*entity.ChatRoom]map[*melody.Session]bool
	sessionChatRoom  map[*melody.Session]*entity.ChatRoom
}

type chatService struct {
	infoMaps chatInfoMaps
	mutex    sync.Mutex
}

var ChatService = chatService{
	infoMaps: chatInfoMaps{
		// 跟session相关的，在websocket请求时更新
		userSession:      make(map[string]*melody.Session),
		sessionUser:      make(map[*melody.Session]string),
		userChatRooms:    make(map[string]map[*entity.ChatRoom]bool), // 用map当set用
		idChatRoom:       make(map[string]*entity.ChatRoom),
		sessionChatRoom:  make(map[*melody.Session]*entity.ChatRoom),
		chatRoomSessions: make(map[*entity.ChatRoom]map[*melody.Session]bool),
	},
}

func (cs *chatService) GetUserBySession(session *melody.Session) string {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()
	return cs.infoMaps.sessionUser[session]
}

func (cs *chatService) GetSessionByUser(account string) *melody.Session {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()
	return cs.infoMaps.userSession[account]
}

func (cs *chatService) GetChatRoomsByUser(account string) []*entity.ChatRoom {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()
	chatRooms := make([]*entity.ChatRoom, 0)
	for k, _ := range cs.infoMaps.userChatRooms[account] {
		chatRooms = append(chatRooms, k)
	}
	return chatRooms
}

func (cs *chatService) GetChatRoomById(id string) *entity.ChatRoom {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()
	return cs.infoMaps.idChatRoom[id]
}

func (cs *chatService) GetChatRoomBySession(session *melody.Session) *entity.ChatRoom {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()
	return cs.infoMaps.sessionChatRoom[session]
}

// GetSessionsByChatRoom 返回该聊天室的所有session
func (cs *chatService) GetSessionsByChatRoom(chatRoom *entity.ChatRoom) []*melody.Session {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()
	sessions := make([]*melody.Session, 0)
	for k, _ := range cs.infoMaps.chatRoomSessions[chatRoom] {
		sessions = append(sessions, k)
	}
	return sessions
}

// GetSessionsBySession 返回该session所在聊天室的所有session
func (cs *chatService) GetSessionsBySession(session *melody.Session) []*melody.Session {
	return cs.GetSessionsByChatRoom(cs.GetChatRoomBySession(session))
}

func (cs *chatService) CreateChatRoom(account string, name string) *entity.ChatRoom {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()
	newChatRoom := &entity.ChatRoom{
		Id:          util.OtherUtil.RandSeq(50),
		Messages:    make([]entity.SentChatMessage, 0),
		Name:        name,
		CreateTime:  time.Now().UnixMilli(),
		HostAccount: account,
	}
	cs.infoMaps.idChatRoom[newChatRoom.Id] = newChatRoom
	if cs.infoMaps.userChatRooms[account] == nil {
		cs.infoMaps.userChatRooms[account] = make(map[*entity.ChatRoom]bool)
	}
	cs.infoMaps.userChatRooms[account][newChatRoom] = true
	return newChatRoom
}

func (cs *chatService) RemoveChatRoom(id string) {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()
	chatRoom := cs.infoMaps.idChatRoom[id]
	if chatRoom == nil {
		return
	}
	account := chatRoom.HostAccount
	// 删除cs.infoMaps.idChatRoom里的相关信息
	delete(cs.infoMaps.idChatRoom, id)
	// 删除cs.infoMaps.userChatRooms里的相关信息
	delete(cs.infoMaps.userChatRooms[account], chatRoom)
	// 删除cs.infoMaps.sessionChatRoom里的相关信息
	for k, _ := range cs.infoMaps.chatRoomSessions[chatRoom] {
		delete(cs.infoMaps.sessionChatRoom, k)
	}
	// 删除cs.infoMaps.chatRoomSessions里的相关信息
	delete(cs.infoMaps.chatRoomSessions, chatRoom)
}

func (cs *chatService) UpdateSession(account string, session *melody.Session, chatRoom *entity.ChatRoom) {
	cs.RemoveSession(session)
	cs.mutex.Lock()
	defer cs.mutex.Unlock()
	cs.infoMaps.userSession[account] = session
	cs.infoMaps.sessionUser[session] = account
	cs.infoMaps.sessionChatRoom[session] = chatRoom
	if cs.infoMaps.chatRoomSessions[chatRoom] == nil {
		cs.infoMaps.chatRoomSessions[chatRoom] = make(map[*melody.Session]bool)
	}
	cs.infoMaps.chatRoomSessions[chatRoom][session] = true
}

func (cs *chatService) RemoveSessionByAccount(account string) {
	cs.mutex.Lock()
	session := cs.infoMaps.userSession[account]
	cs.mutex.Unlock()
	cs.RemoveSession(session)
}

func (cs *chatService) RemoveSession(session *melody.Session) {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()
	delete(cs.infoMaps.userSession, cs.infoMaps.sessionUser[session])
	delete(cs.infoMaps.sessionUser, session)
	chatRoom := cs.infoMaps.sessionChatRoom[session]
	delete(cs.infoMaps.chatRoomSessions[chatRoom], session)
	delete(cs.infoMaps.sessionChatRoom, session)
}

func (cs *chatService) AddMessage(message entity.SentChatMessage, chatRoomId string) {
	chatRoom := cs.GetChatRoomById(chatRoomId)
	cs.mutex.Lock()
	defer cs.mutex.Unlock()
	chatRoom.Messages = append(chatRoom.Messages, message)
}
